#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2018 crane <crane@crane-pc>
#
# Distributed under terms of the MIT license.

"""

"""


import numpy as np
from collections import defaultdict
from math import *
from random import randint


def gen_random_between(total, max):
    '''
        total: 生成多少个随机值,
        max: 这些数的区间是[0, max)
    '''
    # datas = np.random.random([1, total])[0]       # numpy 二维变一维 array
    # return list(datas * max)                    # [0,1) 拉伸到 [0, max)

    results = []
    upper = 20000000000000
    for i in range(total):
        v = randint(0, upper) / upper * max
        results.append(v)
    return results

def p_passion(lambd, n, k):
    '''
    泊松分布中出现k次的概率
    '''
    return (lambd ** k) * (e ** (-lambd)) / factorial(k)

def show_frequence_and_passion(lambd, n, freq_counter):
    ks = range(lambd + 20)  # k的取值 [0, lambd + 20)

    passion_k = map(
        lambda k:p_passion(lambd, n, k),
        ks)

    freq_k = map(
        lambda k: freq_counter[k] / n,
        ks)

    print("passion_k : %s" % list(passion_k))
    print("freq_k    : %s" % list(freq_k))

def between(begin, end, index, data):
    l = len(data)
    cnt = 0
    while index < l:
        value = data[index]
        if begin <= value < end:
            index += 1
            cnt += 1
        else:
            break

    return index, cnt

def passion_anima(lambd, n=100):
    '''
        把事件发生平铺到n次时间线上[0, n) 实数轴上, 每个单位长度1表示一次模拟实验.
        对n次结果频率统计, 取平均频率, 和泊松概率公式比较.
    '''

    # 每个时间段平均发生lambd次, 总共发生lambd * n次
    total = lambd * n
    passion_random_data = gen_random_between(total, n)
    passion_random_data.sort()      # 排序后容易统计
    # print(len(passion_random_data))
    # print(passion_random_data)

    freq_counter = defaultdict(int)      # {times: occurences}   出现的次数和在所有实现中的次数

    # =================== 模拟随机过程, 并统计频率  =====================
    # begin, end = 0, 1
    # for ele in passion_random_data:
    #     if ele < end:
    #         cnt += 1
    #     else:
    #         # 注意这里end 可能直接跑到 end+2
    #         freq_counter[cnt] += 1
    #         cnt = 1
    #         next_end = int(ele) + 1

    # idx = 0
    # cnt = 0
    # for end in range(n):

    # freq_counter[cnt] += 1      # NOTE: 别忘记这里
    # print(freq_counter)

    index = 0
    cnt = 0
    for i in range(n):
        index, cnt = between(i, i+1, index, passion_random_data)
        freq_counter[cnt] += 1
    print(freq_counter)

    # =================== match total =====================
    s = 0
    for key, cnt in freq_counter.items():
        s += key * cnt
    assert  s == total , (s, total)
    # =================== match total =====================

    show_frequence_and_passion(lambd, n, freq_counter)

def main():
    print("start main")

    lambd = 5                # 单位时间内平均发生 lambd次, lambd越大, P(0)越小, 很符合直觉
    n = 110000               # 试验次数: 模拟尽可能多的实现次数, 每次实验是一个符合泊松特征lambda的随机过程.

    passion_anima(lambd, n)

if __name__ == "__main__":
    main()
